package com.anuo.app.modules.study.studyjobschedular;


import com.anuo.app.common.utils.DateUtil;
import com.anuo.app.common.utils.QuartzUtil;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;

import java.util.Date;
import java.util.List;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.JobKey.jobKey;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*;
import static org.quartz.TriggerKey.triggerKey;

/**
 * 研究状态: 常用已掌握
 * @ quartz编码流程:
 *  首先,实现一个 job 见 HelloJob.java , 这个类里面定义要执行的任务
 *  其次,编写如 repeatExecute 方法代码, 实现任务定时执行
 * @ 关闭quartz后, 从数据库恢复执行
 * @ 重复执行(每隔多少秒,分钟,小时,天等等)
 * @ 在指定的时间执行
 * @ 删除定时任务Job
 * @ 异常处理
 * @ 获取所有执行的Job
 * @ 分布式
 */
public class StudyQuartz {

    public static void main(String[] args) {
        deleteJob();
//        runAtCronTrigger();
        //runAtGiveTime();
        //repeatExecute();
        //resumption();
        //repeatExecute();
    }

    /**
     * 关闭quartz后, 从数据库恢复执行
     */
    public static void resumption(){
        //就这么简单
        Scheduler scheduler = QuartzUtil.getScheduler();
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重复执行(每隔多少秒,分钟,小时,天等等)
     */
    public static void repeatExecute() {
        try {
            Scheduler scheduler = QuartzUtil.getScheduler();
            // and start it off
            scheduler.start();
            // define the job and tie it to our HelloJob class
            //注意: 下面的job 和 trigger的 name 和 group 和已有的 不能重复
            JobDetail job = newJob(HelloJob.class)
                    .withIdentity("helloJob", "helloJob")
                    .requestRecovery(true)
                    .build();

            // Trigger the job to run now, and then repeat every 40 seconds
            Date firstDate = DateUtil.strToDate("2017-09-25 16:19:00");
            Trigger trigger = newTrigger()
                    .withIdentity("helloJobTrigger", "helloJob")
                    .startAt(firstDate)
                    .withSchedule(simpleSchedule()
                            .withIntervalInSeconds(6) //在这里可以切换成 时分秒 间隔
                            .repeatForever())
                    .build();

            // Tell quartz to schedule the job using our trigger
            scheduler.scheduleJob(job, trigger);
            //scheduler.shutdown();



        } catch (SchedulerException se) {
            se.printStackTrace();
        }
    }

    /**
     * 在指定的时间执行
     * 比如:每晚12点执行
     */
    public static void runAtGiveTime() {
        Scheduler scheduler = QuartzUtil.getScheduler();
        JobDetail job = newJob(HelloJob.class)
                .withIdentity("helloJob", "helloJob")
                .build();
        Trigger trigger = newTrigger()
                .withIdentity("helloJobTrigger", "helloJob")
                .withSchedule(dailyAtHourAndMinute(23, 59))//在这里指定什么时候执行, 24小时格式
                .forJob(job)
                .build();
        try {
            scheduler.scheduleJob(job, trigger);
            scheduler.start();

        } catch (SchedulerException e) {
            e.printStackTrace();
        }


    }


    /**
     * 用CronTrigger 在每个小时整点执行, 比如9点10点11点执行
     * 参考优质教程: https://www.cnblogs.com/sunjie9606/archive/2012/03/15/2397626.html#undefined
     *      优质教程备用连接: http://blog.csdn.net/u011439289/article/details/43482481
     * 参考官方: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06.html
     * Cron表达式:  http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
     */
    public static void runAtCronTrigger() {
        Scheduler scheduler = QuartzUtil.getScheduler();
        JobDetail job = newJob(HelloJob.class)
                .withIdentity("helloJob", "helloJob")
                .build();
        Trigger trigger = newTrigger()
                .withIdentity("helloJobTrigger", "helloJob")
                .withSchedule(cronSchedule("0 0 8,9,10,11,12 * * ?"))
                .forJob(job)
                .build();
        try {
            scheduler.scheduleJob(job, trigger);
            scheduler.start();

        } catch (SchedulerException e) {
            e.printStackTrace();
        }


    }

    /**
     * 删除定时任务Job
     */
    public static void deleteJob(){
        Scheduler scheduler=QuartzUtil.getScheduler();
        try {
            //删除这个job , 方便下一次调试, 此接口会删除与这个job 相关的所有Trigger
            // 参考: http://www.quartz-scheduler.org/documentation/quartz-2.x/cookbook/UnscheduleJob.html
            scheduler.deleteJob(jobKey("helloJob", "helloJob"));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    /**
     * 异常处理
     * @ 出异常时停止执行
     *      见 HelloJob.java　类的异常处理
     * @ 出异常时改变参数再次运行(感觉不常用)
     *      见:http://www.quartz-scheduler.org/documentation/quartz-2.x/examples/Example6.html BadJob1
     */
    public static void exceptionHandling(){

    }

    /**
     * 获取所有jobs
     * https://stackoverflow.com/questions/22556304/how-to-query-the-scheduled-jobs-from-quartz-scheduler
     */
    public static void getAllExecutingJobs(){
        Scheduler scheduler = QuartzUtil.getScheduler();

        try {
            for (String groupName : scheduler.getJobGroupNames()) {

                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {

                    String jobName = jobKey.getName();
                    String jobGroup = jobKey.getGroup();

                    //get job's trigger
                    List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                    Date nextFireTime = triggers.get(0).getNextFireTime();

                    System.out.println("[jobName] : " + jobName + " [groupName] : "
                            + jobGroup + " - " + nextFireTime);

                }

            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 分布式
     * @ 分布式配置
     * quartz 的分布式配置非常简单, 目前anuoapp 里面的 spring-quartz.xml +
     * quartz.properties 两个文件的配置就是分布式配置,然后在官方包里面有各种数据库的创建脚本(quartz的数据库主要用于实现
     * 分布式锁, 即一台机子执行某个java方法了,集群中的其他机子就不会再执行此方法),这里实践的是MySQL
     * ,已实践有效. 有问题参考
     *      官方: http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering
     * @ 分布式特点
     * quartz 的分布式特点是, 一个job在同一个时间点不会被重复执行, 这样避免重复执行带来的错误和资源浪费
     * 负载均衡这块比较渣, 并不是a,b两个服务器55分执行任务, 更多是一个服务器执行得多,另一个执行的少
     * @ 宕机后恢复执行
     *  搜索当前文件 resumption 方法
     */
    public void quartzDistribute(){

    }
}
